//
// Created by admin on 2022/9/13.
//

#ifndef LEARN_OPENCV_TIMERWHEEL_H
#define LEARN_OPENCV_TIMERWHEEL_H

#include "collection.h"
#include <list>
#include <cassert>
#include <unordered_map>
#include <iostream>
#include <cstring>
#include "thread_pool_cpp.h"

/*时间轮（简易优化版）：
 * 1. 记录ms,ss,min,hour四个维度精度刻度，总长度list[n][msCnt+ssCnt+minCnt+hourCnt]，n代表每个可能可能存在回调函数个数
 * 2. 维护一个map<int,pair>:pair<&list[n],itr> 用于O1快速删除
 * 原理：
 * 1.处理节点都在msCnt维度
 * 2.每个回调函数都应该安置在当前节点的最高为度，在处理时依次下降直到最低维度终止
 * */
namespace TimerWheelUtil {
    static const int MS_UNIT = 1000;
    static const int SECOND_UNIT = 60;
    static const int MIN_UNIT = 60;
    static const int HOUR_UNIT = 24;//时间轮上限

    static const int SECOND_MS_UNIT = SECOND_UNIT * MS_UNIT;
    static const int MIN_SECOND_MS_UNIT = SECOND_MS_UNIT * MIN_UNIT;
    static const int HOUR_MIN_SECOND_MS_UNIT = MIN_SECOND_MS_UNIT * HOUR_UNIT;

    class TimerWheel {
    public:
        /*时间节点*/
        struct TimePos {
            int msPos = 0;
            int ssPos = 0;
            int minPos = 0;
            int hourPos = 0;

            const int gap = 1;

            const int maxMsCnt = MS_UNIT / gap;
            const int maxSsCnt = maxMsCnt + SECOND_UNIT;
            const int maxMinCnt = maxSsCnt + MIN_UNIT;

            long msNow = msPos * gap +
                         ssPos * MS_UNIT +
                         minPos * SECOND_MS_UNIT +
                         hourPos * MIN_SECOND_MS_UNIT;

            TimePos() :
                    msPos(0),
                    ssPos(0),
                    minPos(0),
                    hourPos(0) {

            }

            explicit TimePos(int msPos, int ssPos, int minPos, int hourPos, int gap = 1) : gap(gap),
                                                                                           msPos(msPos),
                                                                                           ssPos(ssPos),
                                                                                           minPos(minPos),
                                                                                           hourPos(hourPos) {
//                assert(MS_UNIT % gap != 0);
//                std::cout << (MS_UNIT % gap) << std::endl;
            }

            TimePos(const TimePos &tp) {
                basePropSet(tp);
                constPropSet(tp.gap);
            }

            TimePos(TimePos &&tp) noexcept {
                basePropSet(tp);
                constPropSet(tp.gap);
            };


            TimePos &operator=(const TimePos &tp) {
                basePropSet(tp);
                constPropSet(tp.gap);
                return *this;
            }

            TimePos &operator=(TimePos &&tp) noexcept {
                basePropSet(tp);
                constPropSet(tp.gap);
                return *this;
            }

            void constPropSet(int gap_) {
                *(int *) &gap = gap_;
                *(int *) &maxMsCnt = MS_UNIT / gap_;
                *(int *) &maxSsCnt = maxMsCnt + SECOND_UNIT;
                *(int *) &maxMinCnt = maxSsCnt + MIN_UNIT;
            }

            void basePropSet(const TimePos &tp) {
                msPos = tp.msPos;
                ssPos = tp.ssPos;
                minPos = tp.minPos;
                hourPos = tp.hourPos;
                msNow = tp.msNow;
            }
            /*效率较低！*/
        private:
            TimePos &add(const TimePos &adder) {
                addMsPos(adder);
                return *this;
            }

            inline void addMsPos(const TimePos &adder) {
                ssPos += (msPos += adder.msPos) / maxMsCnt;
                addSsPos(adder);
                msPos %= maxMsCnt;
            }

            inline void addSsPos(const TimePos &adder) {
                minPos += (ssPos += adder.ssPos) / maxSsCnt;
                addMinPos(adder);
                ssPos %= maxSsCnt;
            }

            inline void addMinPos(const TimePos &adder) {
                hourPos += (minPos += adder.minPos) / maxMinCnt;
                addHourPos(adder);
                minPos %= maxMinCnt;
            }

            inline void addHourPos(const TimePos &adder) {
                hourPos += adder.hourPos;
            }

        public:

            static TimePos ms2TimePos(int gap, long interval) {
                long tmpExistTime = interval;
                return TimePos{tmpExistTime / gap % (MS_UNIT / gap),
                               (tmpExistTime /= MS_UNIT) % SECOND_UNIT,
                               (tmpExistTime /= SECOND_UNIT) % MIN_UNIT,
                               (tmpExistTime /= MIN_UNIT) % HOUR_UNIT, gap};
            }

            TimePos &ms2TimePos(long interval) {
                long tmpExistTime = interval;
                msPos = tmpExistTime / gap % (maxMsCnt);
                ssPos = (tmpExistTime /= MS_UNIT) % SECOND_UNIT;
                minPos = (tmpExistTime /= SECOND_UNIT) % MIN_UNIT;
                hourPos = (tmpExistTime /= MIN_UNIT) % HOUR_UNIT;
                return *this;
            }

            /*获取指针最高级别位置*/
            int absPos() const {
                if (hourPos > 0) {
                    return maxMinCnt + hourPos;
                } else if (minPos > 0) {
                    return maxSsCnt + minPos;
                } else if (ssPos > 0) {
                    return maxMsCnt + ssPos;
                }
                return msPos; //最终都会转换成msPos然后在最低层时间轮被执行
            }

            /*指针降级*/
            TimePos &Degrade(int times = 1) {
                while (times-- > 0) {
                    if (hourPos > 0) {
                        msNow -= MIN_SECOND_MS_UNIT * hourPos;
                        hourPos = 0;
                    } else if (minPos > 0) {
                        msNow -= SECOND_MS_UNIT * minPos;
                        minPos = 0;
                    } else if (ssPos > 0) {
                        msNow -= MS_UNIT * ssPos;
                        ssPos = 0;
                    }
                }
                return *this;
            }

            bool BeHandle() const {
                return !(ssPos | minPos | hourPos);
            }

            bool operator==(const TimePos &rhs) const {
                return hourPos == rhs.hourPos &&
                       minPos == rhs.minPos &&
                       ssPos == rhs.ssPos &&
                       msPos == rhs.msPos;
            }

            TimePos &operator+=(const TimePos &adder) {
                return add(adder);
            }

            TimePos &Add(const TimePos &adder) {
                assert(adder.gap == gap);
                return Add(adder.msNow);
            }

            TimePos &Add(long interval) {
                return ms2TimePos(msNow += interval);
            }

            TimePos &Sub(const TimePos &adder) {
                assert(adder.gap == gap);
                return Sub(adder.msNow);
            }

            TimePos &Sub(long interval) {
                return Add(-interval);
            }


            friend std::ostream &operator<<(std::ostream &os, const TimePos &pos) {
                os << "msPos: " << pos.msPos << " ssPos: " << pos.ssPos << " minPos: " << pos.minPos << " hourPos: "
                   << pos.hourPos;
                return os;
            }
        };

        /*事件节点*/

        struct EventInfo {
            typedef void (*CallBackFunc)(void *);

            CallBackFunc func{nullptr};//回调函数
            void *argP{nullptr};//回调函数入参（默认void*）
            int interval = 0;//间隔时长
            TimePos *timePos = nullptr;//记录时间位点
            int timeId = 0;//timer序号

            EventInfo(int interval, CallBackFunc func, void *argP, TimePos *timePos, int timeId) : interval(interval),
                                                                                                   func(func),
                                                                                                   timePos(timePos),
                                                                                                   timeId(timeId),
                                                                                                   argP(argP) {}

            EventInfo() = default;


            /*除了timepos需要深拷贝，其余都是浅拷贝*/
            EventInfo(const EventInfo &tp) : interval(tp.interval), timeId(tp.timeId), func(tp.func),
                                             timePos(new TimePos(*tp.timePos)), argP(tp.argP) {
            }

            EventInfo(EventInfo &&tp) noexcept: interval(tp.interval), timeId(tp.timeId), func(tp.func),
                                                timePos(std::exchange(tp.timePos, nullptr)), argP(tp.argP) {
            };


            EventInfo &operator=(const EventInfo &tp) {
                return *this = EventInfo(tp);
            }

            EventInfo &operator=(EventInfo &&tp) noexcept {
                interval = tp.interval;
                timeId = tp.timeId;
                func = tp.func;
                argP = tp.argP;
                std::swap(timePos, tp.timePos);
                return *this;
            }


            virtual ~EventInfo() {
                delete this->timePos;
            };

            friend std::ostream &operator<<(std::ostream &os, const EventInfo &info) {
                os << "interval: " << info.interval << " timePos: " << info.timePos;
                return os;
            }

        };

    public:
        TimerWheel() = default;

        virtual ~TimerWheel() {
            /*处理eventCallBackList一定要上锁*/
//            printLn("timePos now: ", timePos_);
            std::lock_guard<std::mutex> ol{mutex_};
            isOk = false;
            delete[] eventCallBackList;
        };

    public:
        /*step 以毫秒为单位，表示定时器最小时间粒度
         *max_timer 表示定时器所能接受的分钟时间间隔
         */
        int initTimerWheel(int step, long existTime);

        /*添加定时器*/
        template<class FN, class ...ARGS>
        int addTimer(int interval, std::tuple<FN, ARGS...> *fnTp) {
            if (interval < stepMs_ || interval % stepMs_ != 0 ||
                interval >= stepMs_ * msGradeCount_ * ssGradeCount_ * minGradeCount_ * hourGradeCount_) {
                std::cout << "time interval is invalid" << std::endl;
                return -1;
            }
            std::lock_guard<std::mutex> ol{mutex_};
            InsertTimer(TimerWheel::EventInfo{interval,
                                              [](void *argP) {
                                                  auto *dp = (std::tuple<FN, ARGS...> *) argP;
                                                  TUPLE2FUNC_DEAL(1, [dp](ARGS ... args) {
                                                      std::get<0>(*dp)(args...);
                                                  }, *dp);
                                              }, fnTp,
                                              new TimerWheel::TimePos(
                                                      TimerWheel::TimePos::ms2TimePos(stepMs_,
                                                                                      timePos_.msNow + interval)),
                                              ++tid});
            return ++cnt;
        }

        template<class FN, class ...ARGS>
        int addTimer(const TimePos &tp, std::tuple<FN, ARGS...> *fnTp) {
            return addTimer(tp.msNow, fnTp);
        }

        /*这里tp特殊处理获取指针，要求只能在主函数调用，否则会有异常*/
        template<class FN, class ...ARGS>
        int
        addTimer(int interval, const std::tuple<FN, ARGS...> &tp) {
            return addTimer(interval, Util::addressOf(tp));
        }

        /*删除定时器*/
        int deleteTimer(int timerId);

    private:
        /*启动循环*/
        [[noreturn]] void DoLoop();

        /*插入定时器*/
        int InsertTimer(const EventInfo &einfo);

        void DealTimeWheeling(std::list<EventInfo> &leinfo);

        static void StaticDealTimeWheeling(TimerWheel *timerWheel, std::list<EventInfo> &leinfo) {
            if (!leinfo.empty()) {
                for (auto &item: leinfo) {
                    //可以处理的情况
                    if (item.timePos->BeHandle()) {
                        timerWheel->pool.commit(*item.func, item.argP);//考虑执行时间防止阻塞
//                        (*item.func)();
                        (*item.timePos = timerWheel->timePos_).Add(item.interval);
                    } else {
                        item.timePos->Degrade();
                    }
                    timerWheel->InsertTimer(item);
                }
                leinfo.clear();
            }
        }

    private:
        bool isOk{true};
        ThreadPool::SimplePool pool{};
        /*timer事件处理列表*/
        std::list<EventInfo> *eventCallBackList = nullptr;
        /*标记清除timer*/
        std::unordered_map<int, std::pair<std::list<EventInfo> *, std::list<EventInfo>::iterator>> timerMap{};
        std::mutex mutex_{};

        // 每次间隔ms值
        int stepMs_ = 1;
        // 维护时钟,从0，0，0，0开始
        TimePos timePos_{0, 0, 0, 0, stepMs_};

        int msGradeCount_ = 0;
        int ssGradeCount_ = 0;
        int minGradeCount_ = 0;
        int hourGradeCount_ = 0;
        // 记录timer数目
        std::atomic<int> cnt{0};
        // timerId
        std::atomic<int> tid{0};
    };


}

#endif //LEARN_OPENCV_TIMERWHEEL_H
